
/************************************************************************************************
 *   深圳市摩西尔电子有限公司 @版本所有@
 *
 *   此文件用于监控页面数据处理
 *
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 巫昭雯
 *      时间 : 2021.11.26
 *      内容 : 所有代码
************************************************************************************************/

/* exported mc_monitor_get_html_color_tip */
/* exported mc_monitor_get_screen_arr */
/* exported mc_monitor_get_side_cnt */
/* exported mc_monitor_modify_range_value */
/* exported mc_monitor_get_hw_data */
/* exported mc_monitor_get_html_range_value_set */
/* exported mc_monitor_reset_err_pkt_cnt */
/* exported mc_io_hw_hub_ext_data */
/* exported mc_io_hw_hub_preset_status */
/* exported obj_format_ext_data */
/* exported mc_scroll_event_tabs */


/* global $ */
/* global mc_sdk_param */
/* global mc_get_hubcard_backup */
/* global mc_ui_item_grp */
/* global mc_sdk_hardware_data */
/* global mc_util_is_array */
/* global set_combo_val */
/* global Swiper */


// 测试代码
var g_test_port_cnt = 0;


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    定义预警项范围值: 颜色&语言id;
 *    用于函数 mc_monitor_modify_range_value & mc_monitor_get_html_range_value_set & mc_monitor_get_html_color_tip
 * 参数:
 *    NA;
 * 返回:
 *    @returns { Promise<String> } 参数1
 * 例子:
 *    NA
 * 备注:
 *    VOL=电压;TEMP=温度;ERROR=误码率
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-12-16
 *       内容 : 所有代码
************************************************************************************************/
var g_obj_warning_param = {
    // [正常范围, 低压预警, 高压预警]
    VOL: {
        "monitor_block_green": "MC_LANG_MONITOR_NORMAL_RANGE",
        "monitor_block_b": "MC_LANG_MONITOR_VOL_MIN",
        "monitor_block_r": "MC_LANG_MONITOR_VOL_MAX"
    },
    // [正常范围, 低温预警, 高温预警]
    TEMP: {
        "monitor_block_green": "MC_LANG_MONITOR_NORMAL_RANGE",
        "monitor_block_b": "MC_LANG_MONITOR_TEMP_MIN",
        "monitor_block_r": "MC_LANG_MONITOR_TEMP_MAX"
    },
    // ["正常值<", "一级预警>","二级预警>"]
    ERROR: {
        "monitor_block_green": "MC_LANG_MONITOR_ERR_NOL",
        "monitor_block_maroon": "MC_LANG_MONITOR_ERR_FIRST",
        "monitor_block_r": "MC_LANG_MONITOR_ERR_SECOND"
    },
    // 获取以上对象内value值组成的数组
    get_value_arr: function (type) {
        var arr = [];
        var obj = this[type];

        if (!obj) {
            return arr;
        }
        for (var key in obj) {
            if (Object.hasOwnProperty.call(obj, key)) {
                arr.push(obj[key]);
            }
        }

        return arr;
    }
};


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    读写分控扩展信息;
 * 参数:
 *    @param { Promise<String> } str_json 请求字串
 *    @param { Promise<Function> } callback 回调(每一项的扩展数据)
 *    @param { Promise<Number> } io 1=写入(目前仅支持清空误码率写入) || 其他为读取; 默认读取
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    回调参数: 若为读取 -> 处理后的数据; 若为写入 -> 直接返回请求json串
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-11-27
 *       内容 : 所有代码
************************************************************************************************/
function mc_io_hw_hub_ext_data(str_json, callback, io) {
    callback = "function" === typeof callback ? callback : function () { };

    var obj_param = new mc_sdk_param();

    obj_param.set_json(str_json);
    obj_param.set_cmd("GET_PARAM");
    obj_param.set_func("HW_HUBCARD_EXT_DATA");

    if (!obj_param.get_param_cnt()) {
        callback(false);
        return;
    }

    if (1 === io) {
        obj_param.set_cmd("SET_PARAM");
    }

    // set attr
    var ui_cnt_set = obj_param.get_param_cnt();

    for (var idx = 0; idx < ui_cnt_set; idx++) {
        var str_name_set = obj_param.get_param_name(idx);

        if (1 === io) {
            obj_param.set_attr_val(str_name_set, "ERR_PKT_CNT", "0");
            continue;
        }
        obj_param.set_attr_val(str_name_set, "VOLTAGE","");
        obj_param.set_attr_val(str_name_set, "TEMPERATURE", "");
        obj_param.set_attr_val(str_name_set, "HUMIDITY", "");
        obj_param.set_attr_val(str_name_set, "ERR_PKT_CNT", "");
        obj_param.set_attr_val(str_name_set, "PORT_STATE", "");
    }

    // console.log("[读写扩展信息]", JSON.parse(obj_param.get_json()));
    $.post("/access_shell", obj_param.get_json(), function (res, status) {
        if ("success" !== status || "function" !== typeof callback) {
            return false;
        }
        if (1 === io) {
            return callback(res);
        }

        var obj_param_res = new mc_sdk_param();

        obj_param_res.set_json(res);

        // 测试代码
        // obj_param_res.set_json(obj_param.get_json());
        // construct_test_resp(obj_param_res);

        // 正式代码
        var ui_cnt = obj_param.get_param_cnt();
        var obj_res = {};

        for (var index = 0; index < ui_cnt; index++) {
            var str_name = obj_param.get_param_name(index);

            obj_res[str_name] = new obj_format_ext_data(str_name, obj_param_res);
        }
        return callback(obj_res);
    }, "text");
}

// ********************************************************************* obj_format_ext_data  ********************************************************************* //
/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    格式化扩展数据 -> 转化为monitor使用数据; 该格式存储扩展数据;
 *    数据格式 {KEY,VOL,TEMP,HUMI,ONOFF,STATUS,DATA_ABNORMAL} =
 *            {请求key,电压,温度,湿度,开关机,排线状态,数据是否异常(电压||湿度||温度至少一项异常)}
 * 参数:
 *    @param { Promise<String> } str_attr_name json串 attr name=请求表达式名称
 *    @param { Promise<Object> } obj_sdk 请求返回字串解析对象 mc_sdk_param
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    1. 内置接口判断数据是否异常:
 *    2. is_abnormal_temp & is_abnormal_humi & is_abnormal_vol 返回值: 0=低于正常值; 1=高于正常值; true=数据异常; false=数据正常;
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-11-27
 *       内容 : 所有代码
************************************************************************************************/
function obj_format_ext_data(str_attr_name, obj_sdk) {
    if (!obj_sdk || "function" !== typeof obj_sdk.get_attr_val || "string" !== typeof str_attr_name || !str_attr_name.trim()) {
        obj_sdk = new mc_sdk_param();
        // 参数异常
        this.PARAM_ERROR = true;
    }

    // ******************** 数据是否异常 ******************** //
    // 判断数据是否异常; 三项至少一项异常;
    this.is_abnormal_data = function () {
        return false !== this.is_abnormal_temp() || false !== this.is_abnormal_humi() || false !== this.is_abnormal_vol();
    };
    // 温度是否异常 // 正常范围取值 0 -> 65; 返回值参考备注
    this.is_abnormal_temp = function () {
        if ("string" !== typeof this.TEMP) {
            return true;
        }
        var arr_val = this.get_range_val().TEMP;

        if (arr_val[0] > this.TEMP) {
            return 0;
        }
        if (arr_val[1] < this.TEMP) {
            return 1;
        }
        return false;
    };
    // 湿度是否异常 // 正常范围取值 0 -> 65; 返回值参考备注
    this.is_abnormal_humi = function () {
        if ("string" !== typeof this.HUMI) {
            return true;
        }
        var arr_val = this.get_range_val().HUMI;

        if (arr_val[0] > this.HUMI) {
            return 0;
        }
        if (arr_val[1] < this.HUMI) {
            return 1;
        }
        return false;
    };
    // 电压是否异常 // 正常范围取值 4 -> 4.4; 返回值参考备注
    this.is_abnormal_vol = function () {
        if ("string" !== typeof this.VOL) {
            return true;
        }
        var arr_val = this.get_range_val().VOL;

        if (arr_val[0] > this.VOL) {
            return 0;
        }
        if (arr_val[1] < this.VOL) {
            return 1;
        }
        return false;
    };

    // 误码率是否异常 // 正常范围取值 <100  返回值参考备注 0=正常; 1=一级预警; 2=2级预警; false=其他数据
    this.is_abnormal_error_pro = function () {
        if ("string" !== typeof this.ERROR) {
            return true;
        }
        var arr_val = this.get_range_val().ERROR;

        if (this.ERROR <= arr_val[0]) {
            return 0;
        }
        if (this.ERROR > arr_val[1]) {
            return 2;
        }
        if (this.ERROR > arr_val[0]) {
            return 1;
        }
        return false;
    };

    // 请求key
    this.KEY = str_attr_name;
    // 电压 & 温度 & 湿度 & 通信状态 & 开关机时间 & 误码率
    this.VOL = obj_sdk.get_attr_val(str_attr_name, "VOLTAGE");
    this.TEMP = obj_sdk.get_attr_val(str_attr_name, "TEMPERATURE");
    this.HUMI = obj_sdk.get_attr_val(str_attr_name, "HUMIDITY");
    this.STATUS = parse_status(obj_sdk.get_attr_val(str_attr_name, "PORT_STATE"));
    this.ONOFF = obj_sdk.get_attr_val(str_attr_name, "ONOFFLOG");
    this.ERROR = obj_sdk.get_attr_val(str_attr_name, "ERR_PKT_CNT");
    // 数据异常; 电压 || 湿度 || 温度 至少一项异常
    this.DATA_ABNORMAL = this.is_abnormal_data();

    // 排线是否正常; str_port_status 请求返回的排线状态值
    // @returns true=正常 || false=异常
    this.is_normal_statu = function (str_port_status) {
        if ("string" !== typeof str_port_status) {
            return false;
        }
        str_port_status = str_port_status.trim();
        if (!str_port_status) {
            return false;
        }
        var arr_statu = str_port_status.split(",");
        var ui_len = arr_statu.length;

        for (var idx = 0; idx < ui_len; idx++) {
            if (1 !== Number(arr_statu[idx])) {
                return false;
            }
        }
        return true;
    };

    // 解析PORT_STATE数据; 获取状态数组;
    // @returns [该端口正常, 异常, ...]=[true=正常, false=异常]
    function parse_status(str_p) {
        if ("string" !== typeof str_p || !str_p.trim()) {
            return [];
        }
        var arr_statu = str_p.split(",");
        var ui_len = arr_statu.length;

        for (var idx = 0; idx < ui_len; idx++) {
            if (1 === Number(arr_statu[idx])) {
                arr_statu[idx] = true;
            } else {
                arr_statu[idx] = false;
            }
        }
        return arr_statu;
    }
}

/************************************************************************************************
 * 类型:
 *    构造函数属性
 * 功能:
 *    obj_format_ext_data.prototype 以下属性设置用于预警范围值读写: 均存储于localStorage
 * 参数:
 *    NA
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    以下标记: VOL=电压; TEMP=温度; HUMI=湿度;
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-12-14
 *       内容 : 所有代码
 ************************************************************************************************/
// 初始化范围值;
// @param { Promise<Boolean> } b_modify 是否为修改; 默认为空; 若为true, 则将存储的预警范围值修改为当前设置的范围值
obj_format_ext_data.prototype.init = function (b_modify) {
    var str_name = "MC_MONITOR_RANGE_VAL";

    if (b_modify) {
        localStorage.setItem(str_name, JSON.stringify(this.range_val));
    } else {
        if (!localStorage.getItem(str_name)) {
            localStorage.setItem(str_name, JSON.stringify(obj_format_ext_data.prototype.range_val));
        } else {
            obj_format_ext_data.prototype.range_val = JSON.parse(localStorage.getItem(str_name));
        }
    }
};
// 范围值初始值; 一般不直接于外部使用，若需要使用或修改可调用 get_range_val || set_range_val
obj_format_ext_data.prototype.range_val = {
    // 电压, 温度，湿度 [min, max]
    VOL: [4, 4.4],
    TEMP: [0, 65],
    HUMI: [0, 65],
    // 三个阶段值 0-100 || 10-1000 || >1000
    ERROR: [100, 1000]
};
// 获取范围值; 返回 range_val
obj_format_ext_data.prototype.get_range_val = function () {
    return this.range_val;
};
// 获取设置的区域值(该值限制编辑框的大小值); 根据常识特殊处理;
obj_format_ext_data.prototype.get_area_val = function () {
    // 电压, 温度，湿度 [min, max]
    return {
        VOL: [1, 380],
        TEMP: [-50, 100],
        HUMI: [0, 65],
        ERROR: [1, null]
    };
};
/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    设置范围值;
 * 参数:
 *    @param { Promise<String> } type 设置类型: 与 range_val 属性一致
 *    @param { Promise<Number> } min_val 最小值
 *    @param { Promise<Number> } max_val 最大值
 * 返回:
 *    @returns { Promise<Number> } 0=设置值有误; 1=设置成功; 2=设置值与原来值相同
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-12-15
 *       内容 : 所有代码
************************************************************************************************/
obj_format_ext_data.prototype.set_range_val = function (type, min_val, max_val) {
    if ("number" !== typeof min_val || "number" !== typeof max_val || isNaN(min_val) || isNaN(max_val)) {
        return 0;
    }
    if (min_val >= max_val) {
        return 0;
    }
    if (!mc_util_is_array(this.range_val[type])) {
        return 0;
    }
    if (this.range_val[type][0] === min_val && this.range_val[type][1] === max_val) {
        return 2;
    }
    // 根据常识特殊处理;
    switch (type) {
    case "VOL":
        if (380 < max_val || 0 >= min_val) {
            return 0;
        }
        break;
    case "TEMP":
        if (100 < max_val) {
            return 0;
        }
        break;
    case "ERROR":
        if (0 >= min_val) {
            return 0;
        }
        break;
    default:
        break;
    }
    this.range_val[type] = [min_val, max_val];
    this.init(true);
    return 1;
};
new obj_format_ext_data().init();
// ********************************************************************* obj_format_ext_data range value ********************************************************************* //


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取颜色提示解释html;
 * 参数:
 *    @param { Promise<String> } type obj_tabs_menu_left[ui_select_tab] 当前左侧标签选中类型
 * 返回:
 *    @returns { Promise<String> } dom html字串
 * 例子:
 *    NA
 * 备注:
 *    type=HUB_CNT 标识分控提示
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-12-02
 *       内容 : 所有代码
************************************************************************************************/
function mc_monitor_get_html_color_tip(type) {
    // obj_color颜色解释对象 key=颜色块类, value=lang_id;
    var obj_color = {
        // "monitor_block_grey": "MC_LANG_MONITOR_COLOR_DATA_ERROR",
        "monitor_block_b": "MC_LANG_MONITOR_COLOR_NORMAL",
        "monitor_block_r": "MC_LANG_MONITOR_COLOR_ERROR",
        "monitor_block_green": "MC_LANG_MONITOR_COLOR_DATA_ERROR"
    };

    switch (type) {
    case "VOL":
        obj_color = g_obj_warning_param.VOL;
        break;
    case "TH":
        obj_color = g_obj_warning_param.TEMP;
        break;
    case "HUB_CNT":
        obj_color = {
            "hw_more_save": "MC_LANG_MONITOR_TIP_HW_MORE",
            "save_more_hw": "MC_LANG_MONITOR_TIP_HW_LESS"
        };
        break;
    case "ERROR":
        obj_color = g_obj_warning_param.ERROR;
        break;
    default:
        obj_color = {};
        break;
    }
    var str_html = "<div class='flex_box_horizontal tip_color_wrap' >";

    for (var key in obj_color) {
        if (Object.hasOwnProperty.call(obj_color, key)) {
            var lang_id = obj_color[key];

            if (lang_id) {
                str_html += "" +
                "<div class='flex_box_horizontal tip_item'>" +
                "<span class='tip_color " + key + "'></span>" +
                "<span class='tip_color_txt' lang_id='" + lang_id + "'>" + lang_id + "</span>" +
                "</div>";
            }
        }
    }
    return str_html + "</div>";
}


// 标签页滚动条事件
function mc_scroll_event_tabs() {
    // .btn_tabs_wrap  touchmove
    var m_obj_swiper = null;
    var fn_init = function () {
        // if (mc_istouch()) {
        //     return;
        // }

        var obj_gp = $(".layout_right .btn_tabs_wrap");

        if (!obj_gp.length) {
            return;
        }

        obj_gp.parent().addClass("swiper-container");
        obj_gp.addClass("swiper-wrapper");

        var str_div = "<div class='btn_tab placeholder' lang_id='' style='pointer-events: none;'></div>";

        // obj_gp.prepend(str_div).append(str_div);
        obj_gp.append(str_div);

        $(".layout_right .btn_tabs_wrap .btn_tab").each(function () {
            if ("none" !== this.style.display) {
                $(this).addClass("swiper-slide");
            }
        });

        m_obj_swiper = new Swiper(".swiper-container", {
            slidesPerView: "auto",
            observer: true,
            roundLengths: true,
            // 因为仅有1个slide，swiper无效
            watchOverflow: true,
            // 边缘抵抗值
            resistanceRatio: 0.5,
            // 鼠标滚轮
            mousewheel: {
                sensitivity: 1.5
            },
            // 监听
            on: {
                resize: function () {
                    //窗口变化时，更新Swiper的一些属性，如宽高等
                    this.update();
                }
            }
        });
    };

    fn_init();

    this.update = function () {
        if (m_obj_swiper) {
            m_obj_swiper.update();
        }
    };

    this.slideTo = function (idx) {
        if (m_obj_swiper) {
            m_obj_swiper.slideTo(idx);
        }
    };
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取全局提示异常数据;
 * 参数:
 *    @param { Promise<Array> } arr_data 所有屏数据
 * 返回:
 *    @returns { Promise<String> } str html
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-12-08
 *       内容 : 所有代码
************************************************************************************************/
function mc_monitor_get_error_tip_html(arr_data) {   /* eslint-disable-line */
    if ("object" !== typeof arr_data) {
        return "";
    }

    var ui_len = arr_data.length;

    if (!ui_len) {
        return "";
    }

    var str_html = [];

    for (var idx = 0; idx < ui_len; idx++) {
        var obj_data = arr_data[idx];

        if (!obj_data) {
            continue;
        }

        // 临时扩展数据
        var obj_temp = null;

        for (var key in obj_data) {
            if (Object.hasOwnProperty.call(obj_data, key)) {
                var obj_ext_data = obj_data[key];

                if (!obj_ext_data || !(obj_temp = obj_ext_data.EXPAND)) {
                    continue;
                }

                var str_def = "<span lang_id='MC_LANG_MONITOR_BOX_IDX'>箱体</span>" + obj_ext_data.BOX_IDX + "(" + (idx + 1) + "-" + obj_ext_data.PORT + ")" + "<span lang_id='MC_LANG_MONITOR_TIPS_ERROR_ITEM'>异常项</span>:";
                var str_port = str_def;

                if (obj_temp.DATA_ABNORMAL) {
                    str_port += "<span lang_id='MC_LANG_MONITOR_TIPS_ERROR_THV'>温度,湿度,电压,</span>";
                }

                if (!obj_temp.is_normal_statu(obj_temp.STATUS)) {
                    str_port += "<span lang_id='MC_LANG_MONITOR_TIPS_ERROR_STATU'>排线</span>";
                }

                if (str_port !== str_def) {
                    str_html.push(str_port);
                }
            }
        }
    }

    if (str_html.length) {
        return str_html.join(", ");
    }
    return str_html;
}


// ********************************************************************* V1 ********************************************************************* //
/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取屏标签数组(发送卡信息标签);
 * 参数:
 *    @param { Promise<Array> } arr_info 硬件获取的发送卡信息;  =new mc_sdk_hardware_data().get_hw_state() 获取的数据
 *    @param { Promise<Function> } fn_callback 回调函数; 参数obj_send_data=标签数据对象;
 * 返回:
 *    @returns { Promise<String> } 参数1
 * 例子:
 *    NA
 * 备注:
 *    若当前无发送卡 -> 返回一条空的标签数据; 外部可以无需空卡处理,直接使用
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-12-13
 *       内容 : 所有代码
************************************************************************************************/
function mc_monitor_get_screen_arr(arr_info, fn_callback) {
    fn_callback = "function" === typeof fn_callback ? fn_callback : function () { };

    var obj_tabs_screen = {};
    var str_def = "--";
    var ui_len_send = 1;

    // arr_info=发送卡信息
    if (mc_util_is_array(arr_info) && arr_info.length) {
        ui_len_send = arr_info.length;
    } else {
        arr_info = [];
    }

    for (var idx_s = 0; idx_s < ui_len_send; idx_s++) {
        var obj_info = arr_info[idx_s] || {};
        var str_screen = "<div>" + "<span lang_id='MC_LANG_MONITOR_SCREEN'>屏</span>" + (idx_s + 1) + " [" + (obj_info.name || str_def) + "]" + "</div>";
        var str_type = "<div>" + "<span lang_id='MC_LANG_CARD_INFO_TYPE'>类型</span> " + " [" + (obj_info.card_type || str_def) + "]" + "</div>";
        var str_id = "<div>" + "<span lang_id='MC_LANG_CARD_INFO_ID'>ID</span> " + " [" + (obj_info.id || str_def) + "]" + "</div>";

        obj_tabs_screen[idx_s] = "<div class='tab_val_wrap'>" + str_screen + str_type + str_id + "</div>";
    }
    return fn_callback(obj_tabs_screen);
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    读取硬件连接的hub卡 & 获取监控数据;
 * 参数:
 *    @param { Promise<Object> } obj_hw_data 硬件连接状态实例对象
 *    @param { Promise<Number> } ui_send_idx 当前发送卡(屏)下标; 从0开始
 *    @param { Promise<Function> } fn_callback 回调函数; 参数(数据对象, 最大行值, 最大列值);
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    1. 回调返回数对象格式 {端口:[hub卡1={}, hub卡2={},...], 端口2:[...]};  (*端口内卡数组=按照连线顺序排列)
 *    每个hub卡数据对象: { X,Y,NAME,IDX,KEY,HUB_BACKUP,EXPADN:{KEY,VOL,HUMI,TEMP....},IMG_RECT };
 *                      { X轴值,Y轴值,HUB名称,请求key,是否备份,扩展数据(请求key,电压,湿度,温度等数据),图像配置[X,Y,W,H] }
 *    示例 { P1:[{X:1, Y:2, NAME:"H1", KEY:"0:1:1", IDX:1, HUB_BACKUP:TRUE, EXPAND:{obj_format_ext_data}, IMG_RECT:[0,1,64,64]}],  P2:[...] }
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-12-13
 *       内容 : 所有代码
************************************************************************************************/
function mc_monitor_get_hw_data(obj_hw_data, ui_send_idx , fn_callback ) {
    fn_callback = "function" === typeof fn_callback ? fn_callback : function () { };
    if ("number" !== typeof ui_send_idx || "object" !== typeof obj_hw_data || !(obj_hw_data instanceof mc_sdk_hardware_data)) {
        return;
    }

    // result data
    var obj_data = {};
    var ui_send_port = obj_hw_data.get_port_cnt(ui_send_idx) || g_test_port_cnt;
    var str_line_key = "";
    var ui_cnt_hub = 0;
    var ui_cnt_hub_port = 0;
    var max_col = 0, max_row = ui_send_port;
    // 请求字串
    var obj_sdk_param_req = new mc_sdk_param();
    var str_req_key = "";

    for (var idx_sp = 0; idx_sp < ui_send_port; idx_sp++) {
        str_line_key = "P" + (idx_sp + 1);
        // str_line_key = (idx_sp + 1);
        obj_data[str_line_key] = [];
        ui_cnt_hub = obj_hw_data.get_hub_cnt(ui_send_idx, idx_sp);
        // 测试代码
        // ui_cnt_hub = Math.ceil(Math.random() * 10);
        if (ui_cnt_hub > max_col) {
            max_col = ui_cnt_hub;
        }
        for (var idx_h = 0; idx_h < ui_cnt_hub; idx_h++) {
            // "0:0:0"= send + port + hub
            str_req_key = ui_send_idx + ":" + idx_sp + ":" + idx_h;
            ui_cnt_hub_port = obj_hw_data.get_hub_prot_cnt(ui_send_idx, idx_sp, idx_h);
            // save value
            obj_data[str_line_key].push({
                NAME: "H" + (idx_h + 1),
                IDX: (idx_h + 1),
                KEY: str_req_key,
                X: idx_h + 1,
                Y: idx_sp + 1,
                HUB_BACKUP: false,
                HUB_PORT_CNT: ui_cnt_hub_port,
                IMG_RECT: null
            });
            obj_sdk_param_req.set_param_value(str_req_key, str_req_key);
        }
    }

    var obj_sdk_param_res = new mc_sdk_param();
    var str_json = obj_sdk_param_req.get_json();

    // hub ext data & hub backup
    mc_io_hw_hub_ext_data(str_json, function (obj_resp) {
        for (var key in obj_resp) {
            if (Object.hasOwnProperty.call(obj_resp, key)) {
                var item_res = obj_resp[key];

                if (item_res && (item_res.KEY)) {
                    save_data(item_res.KEY, item_res, "ext");
                }
            }
        }
        return get_hub_backup();
    });

    // hub backup
    function get_hub_backup() {
        return mc_get_hubcard_backup(str_json, function (str_json_res) {
            return deal_response(str_json_res, "backup");
        });
    }

    // img rect;
    function get_hub_rect() {   /* eslint-disable-line */
        return mc_io_hw_hub_img_rect(str_json, function (str_json_res) {
            return deal_response(str_json_res, "rect");
        });
    }

    function fn_done() {
        // console.log(obj_data); /* eslint-disable-line */
        return fn_callback(obj_data, max_row, max_col);
    }

    // 封装处理请求返回结果
    // @param str_json_res 请求返回json串
    // @param type 处理数据类型=调用save_data参数;
    // @param fn_next 处理下一个函数调用; 若为空->结束&返回数据(调用fn_done)
    function deal_response(str_json_res, type, fn_next) {
        fn_next = "function" === typeof fn_next ? fn_next : fn_done;
        obj_sdk_param_res.set_param_clear();
        obj_sdk_param_res.set_json(str_json_res);
        var ui_cnt_res = obj_sdk_param_res.get_param_cnt();

        for (var i_h = 0; i_h < ui_cnt_res; i_h++) {
            var str_key = obj_sdk_param_res.get_param_name(i_h);

            save_data(str_key, obj_sdk_param_res.get_param_value(str_key), type);
        }
        return fn_next();
    }

    // 保存数据
    // @param str_key 请求key
    // @param data 数据; 请求value值
    // @param type=ext为存储扩展数据, backup=存储hub backup; rect=图像区域信息
    function save_data(str_key, data, type) {
        var arr_idx = str_key.split(":");

        str_line_key = "P" + (Number(arr_idx[1]) + 1);
        var obj_temp = null;

        if (!obj_data[str_line_key] || !(obj_temp = obj_data[str_line_key][arr_idx[2]]) || obj_temp.KEY !== str_key) {
            return;
        }

        switch (type) {
        case "ext":
            // EXPAND 扩展参数; obj_format_ext_data
            obj_data[str_line_key][arr_idx[2]].EXPAND = data;
            return;
        case "backup":
            // save hubback; true=开启备份
            // 测试代码 data = 0 === (Math.random() * 10).toFixed(0) % 2 ? "1" : "0";
            if ("0" === data) {
                obj_data[str_line_key][arr_idx[2]].HUB_BACKUP = true;
            }
            return;
        case "rect":
            // save img rect;
            if ("string" === typeof data && data.trim()) {
                obj_data[str_line_key][arr_idx[2]].IMG_RECT = data.split(":");
            }
            return;
        default:
            return;
        }
    }
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取侧边分控通统计html
 * 参数:
 *    @param { Promise<Object> } obj_hw_data 硬件连接实例对象
 *    @param { Promise<Number> } ui_send_idx 当前屏(发送卡)下标
 *    @param { Promise<Function> } fn_callback 回调(str_html)
 * 返回:
 *    @returns { Promise<Boolean> } false=参数错误
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-12-14
 *       内容 : 所有代码
************************************************************************************************/
function mc_monitor_get_side_cnt(obj_hw_data, ui_send_idx, fn_callback) {
    fn_callback = "function" === typeof fn_callback ? fn_callback : function () { };
    if ("number" !== typeof ui_send_idx || "object" !== typeof obj_hw_data || !(obj_hw_data instanceof mc_sdk_hardware_data)) {
        return fn_callback(false);
    }

    var obj_param = new mc_sdk_param();

    obj_param.set_param_value(ui_send_idx + "", " ");

    // 获取已经固化的显示屏分控数量
    return mc_io_hw_hub_preset_status(obj_param.get_json(), function (str_json) {
        obj_param.set_param_clear();
        obj_param.set_json(str_json);
        var ui_send_port = obj_hw_data.get_port_cnt(ui_send_idx) || g_test_port_cnt;
        var str_hub = obj_param.get_param_value(ui_send_idx + "") || construct_test_hub(ui_send_port);
        var arr_hub = str_hub.split(",");
        var str_html = "";
        var ui_save_hub = 0;
        var ui_cnt_hub = 0;
        var str_html_inder = "";

        for (var idx_sp = 0; idx_sp < ui_send_port; idx_sp++) {
            ui_cnt_hub = obj_hw_data.get_hub_cnt(ui_send_idx, idx_sp);
            ui_save_hub = Number(arr_hub[idx_sp]) || 0;
            str_html_inder = "<div class='inner_val'>" + "<b>" + "P" + (idx_sp + 1) + "</b>" + "<br/>" + ui_save_hub + "/" + ui_cnt_hub + "</div>";
            if (ui_save_hub === ui_cnt_hub) {
                str_html += "<div class='side_block'>" + str_html_inder + "</div>";
            } else {
                if (ui_save_hub > ui_cnt_hub) {
                    str_html += "<div class='side_block save_more_hw'>" + str_html_inder + "</div>";
                } else {
                    str_html += "<div class='side_block hw_more_save'>" + str_html_inder + "</div>";
                }
            }
        }
        return fn_callback(str_html);
    });
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取范围值设置html; 在改函数内处理范围值修改
 * 参数:
 *    @param { Promise<Object> } obj_igp  mc_ui_item_grp 实例
 *    @param { Promise<String> } str_type 当前页面左侧选中的类型
 * 返回:
 *    @returns { Promise<String> } string html
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-12-15
 *       内容 : 所有代码
************************************************************************************************/
function mc_monitor_get_html_range_value_set(obj_igp, str_type) {
    if ("object" !== typeof obj_igp || !(obj_igp instanceof mc_ui_item_grp) ) {
        return "";
    }

    var obj_range_data = new obj_format_ext_data();
    var obj_sdk_param = new mc_sdk_param();
    var str_param_name = "";
    var arr_param_name = [];
    var arr_min_max = null;
    var arr_area = null;
    var str_tail = "";

    switch (str_type) {
    case "VOL":
        // 电压;  [正常范围, 低压预警, 高压预警]
        arr_param_name = g_obj_warning_param.get_value_arr("VOL");
        arr_min_max = obj_range_data.get_range_val().VOL;
        arr_area = obj_range_data.get_area_val().VOL;
        str_tail = "V";
        break;
    case "TH":
        // 温湿度; 主要设置温度; [正常范围, 低温预警, 高温预警]
        arr_param_name = g_obj_warning_param.get_value_arr("TEMP");
        arr_min_max = obj_range_data.get_range_val().TEMP;
        arr_area = obj_range_data.get_area_val().TEMP;
        str_tail = "℃";
        break;
    case "ERROR":
        // 误码率 ["正常值<", "一级预警>","二级预警>"]
        arr_param_name = g_obj_warning_param.get_value_arr("ERROR");
        arr_min_max = obj_range_data.get_range_val().ERROR;
        arr_area = obj_range_data.get_area_val().ERROR;
        return get_error_pro();
    default:
        return "";
    }

    // range
    str_param_name = arr_param_name[0];
    obj_sdk_param.set_param_value(str_param_name, arr_min_max[0] + " — " + arr_min_max[1]);
    obj_sdk_param.set_attr_val(str_param_name, "UI_TYPE", "LABEL");
    obj_sdk_param.set_attr_val(str_param_name, "TAIL_ID_LIST", str_tail);
    // min
    str_param_name = arr_param_name[1];
    obj_sdk_param.set_param_value(str_param_name, arr_min_max[0] + "");
    obj_sdk_param.set_attr_val(str_param_name, "UI_TYPE", "EDIT");
    obj_sdk_param.set_attr_val(str_param_name, "VAL_TYPE", "float");
    obj_sdk_param.set_attr_val(str_param_name, "TAIL_ID_LIST", str_tail);
    obj_sdk_param.set_attr_val(str_param_name, "MIN_VAL", arr_area[0] + "");
    // max
    str_param_name = arr_param_name[2];
    obj_sdk_param.set_param_value(str_param_name, arr_min_max[1] + "");
    obj_sdk_param.set_attr_val(str_param_name, "UI_TYPE", "EDIT");
    obj_sdk_param.set_attr_val(str_param_name, "VAL_TYPE", "float");
    obj_sdk_param.set_attr_val(str_param_name, "TAIL_ID_LIST", str_tail);
    obj_sdk_param.set_attr_val(str_param_name, "MAX_VAL", arr_area[1] + "");

    var str_json = obj_sdk_param.get_json();

    obj_igp.set_rgb_combo_mode(set_combo_val(str_json, true));
    obj_igp.set_max_col_cnt(1);
    obj_igp.set_item_unit_width("20px");
    obj_igp.set_json_txt(str_json);
    obj_igp.on_val_chg = function () {
        var obj_sdk_param_edit = new mc_sdk_param();

        obj_sdk_param_edit.set_json(obj_igp.get_json_txt());
        obj_sdk_param_edit.set_param_value(arr_param_name[0], obj_sdk_param_edit.get_param_value(arr_param_name[1]) + " — " + obj_sdk_param_edit.get_param_value(arr_param_name[2]) );
        obj_igp.update_dom_val(obj_sdk_param_edit.get_json());
    };

    // var str_html_btn = "<div class='icon_btn icon-btn-apply' lang_id='MC_LANG_BTN_APPLY' onclick='mc_monitor_btn_clk_range_set_ok(" + obj_igp + ")' > <div><span lang_id='MC_LANG_BTN_APPLY' >应用</span></div></div>";
    return "<div class='monitor_igp_wrap'>" + obj_igp.get_dom_html() + "</div>";

    // 误码率
    function get_error_pro() {
        // range
        str_param_name = arr_param_name[0];
        obj_sdk_param.set_param_value(str_param_name, arr_min_max[0] + "");
        obj_sdk_param.set_attr_val(str_param_name, "UI_TYPE", "EDIT");
        obj_sdk_param.set_attr_val(str_param_name, "VAL_TYPE", "float");
        obj_sdk_param.set_attr_val(str_param_name, "MIN_VAL", arr_area[0] + "");
        // first
        str_param_name = arr_param_name[1];
        obj_sdk_param.set_param_value(str_param_name, arr_min_max[0] + "");
        obj_sdk_param.set_attr_val(str_param_name, "UI_TYPE", "LABEL");
        // second
        str_param_name = arr_param_name[2];
        obj_sdk_param.set_param_value(str_param_name, arr_min_max[1] + "");
        obj_sdk_param.set_attr_val(str_param_name, "UI_TYPE", "EDIT");
        obj_sdk_param.set_attr_val(arr_param_name[1], "VAL_TYPE", "float");
        obj_sdk_param.set_attr_val(str_param_name, "MAX_VAL", arr_area[1] + "");

        var str_json_err = obj_sdk_param.get_json();

        obj_igp.set_rgb_combo_mode(set_combo_val(str_json_err, true));
        obj_igp.set_max_col_cnt(1);
        obj_igp.set_item_unit_width("8px");
        obj_igp.set_json_txt(str_json_err);
        obj_igp.on_val_chg = function (lang_id, val) {
            if (arr_param_name[0] === lang_id) {
                var obj_sdk_param_edit = new mc_sdk_param();

                obj_sdk_param_edit.set_json(obj_igp.get_json_txt());
                obj_sdk_param_edit.set_param_value(arr_param_name[1], val + "");
                obj_igp.update_dom_val(obj_sdk_param_edit.get_json());
            }
        };

        return "<div class='monitor_igp_wrap'>" + obj_igp.get_dom_html() + "</div>";
    }
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    范围值设置确定按钮; 修改存储的范围值
 * 参数:
 *    @param { Promise<Object> } obj_igp 按钮组实例对象
 *    @param { Promise<String> } str_type 当前页面左侧选择的标签
 * 返回:
 *    @returns { Promise<Number> } 0=设置值有误; 1=设置成功; 2=设置值与原来值相同
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-12-15
 *       内容 : 所有代码
************************************************************************************************/
function mc_monitor_modify_range_value(obj_igp, str_type) {
    if ("object" !== typeof obj_igp || !(obj_igp instanceof mc_ui_item_grp)) {
        return false;
    }

    var arr_param_name = [];
    var str_set_range = "";

    switch (str_type) {
    case "VOL":
        // 电压
        arr_param_name = g_obj_warning_param.get_value_arr("VOL");
        str_set_range = "VOL";
        break;
    case "TH":
        // 温湿度; 主要设置温度
        arr_param_name = g_obj_warning_param.get_value_arr("TEMP");
        str_set_range = "TEMP";
        break;
    case "ERROR":
        // 误码率
        arr_param_name = g_obj_warning_param.get_value_arr("ERROR");
        str_set_range = "ERROR";
        break;
    default:
        return false;
    }

    var obj_sdk_param_edit = new mc_sdk_param();

    obj_sdk_param_edit.set_json(obj_igp.get_json_txt());
    var ui_min = obj_sdk_param_edit.get_param_value(arr_param_name[1]);
    var ui_max = obj_sdk_param_edit.get_param_value(arr_param_name[2]);
    var obj_data = new obj_format_ext_data();
    // set range
    var b_res = obj_data.set_range_val(str_set_range, Number(ui_min), Number(ui_max));

    if (0 === b_res) {
        // if set err -> update dom use old value
        var obj_value = obj_data.get_range_val();

        // value & min & max
        if ("ERROR" === str_type) {
            obj_sdk_param_edit.set_param_value(arr_param_name[0], obj_value[str_set_range][0] + "");
            obj_sdk_param_edit.set_param_value(arr_param_name[1], obj_value[str_set_range][0] + "");
            obj_sdk_param_edit.set_param_value(arr_param_name[2], obj_value[str_set_range][1] + "");
        } else {
            obj_sdk_param_edit.set_param_value(arr_param_name[0], obj_value[str_set_range][0] + " — " + obj_value[str_set_range][1]);
            obj_sdk_param_edit.set_param_value(arr_param_name[1], obj_value[str_set_range][0] + "");
            obj_sdk_param_edit.set_param_value(arr_param_name[2], obj_value[str_set_range][1] + "");
        }
        obj_igp.update_dom_val(obj_sdk_param_edit.get_json());
    }

    return b_res;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    清空误码率;
 * 参数:
 *    @param { Promise<Object> } obj_data 当前屏数据; mc_monitor_get_hw_data 返回的数据对象
 *    @param { Promise<Function> } fn_callback
 * 返回:
 *    @returns { Promise<String> } 参数1
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-12-17
 *       内容 : 所有代码
************************************************************************************************/
function mc_monitor_reset_err_pkt_cnt(obj_data, fn_callback) {
    fn_callback = "function" === typeof fn_callback ? fn_callback : function () { };
    if ("object" !== typeof obj_data) {
        return fn_callback(false);
    }

    var obj_sdk_param = new mc_sdk_param();
    var ui_cnt = 0;
    var arr_data = null;
    var obj_i = null;

    for (var key in obj_data) {
        if (Object.hasOwnProperty.call(obj_data, key)) {
            arr_data = obj_data[key];

            if (!arr_data) {
                continue;
            }
            ui_cnt = arr_data.length;
            for (var idx = 0; idx < ui_cnt; idx++) {
                obj_i = arr_data[idx];

                if (!obj_i || !obj_i.KEY) {
                    continue;
                }

                obj_sdk_param.set_param_value(obj_i.KEY, obj_i.KEY);
                // obj_sdk_param.set_attr_val(obj_i.KEY, "ERR_PKT_CNT", "0");
            }
        }
    }

    if (!obj_sdk_param.get_param_cnt()) {
        return fn_callback(false);
    }

    return mc_io_hw_hub_ext_data(obj_sdk_param.get_json(), function () {
        return fn_callback(true);
    }, 1);
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    读写分控预设数量; hub卡
 * 参数:
 *    @param { Promise<String> } str_json 请求字串;
 *    @param { Promise<Function> } callback 回调; 直接返回response
 *    @param { Promise<Number> } io 1=写入 || 其他为读取; 默认读取
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-12-22
 *       内容 : 所有代码
************************************************************************************************/
function mc_io_hw_hub_preset_status(str_json, callback, io) {
    callback = "function" === typeof callback ? callback : function () { };

    var obj_param = new mc_sdk_param();

    obj_param.set_json(str_json);
    obj_param.set_cmd("GET_PARAM");
    obj_param.set_func("HW_HUBCARD_SAVED_STATUS");

    if (!obj_param.get_param_cnt()) {
        callback(false);
        return;
    }

    if (1 === io) {
        obj_param.set_cmd("SET_PARAM");
    }

    // console.log("[读写分控数量]", JSON.parse(obj_param.get_json()));
    $.post("/access_shell", obj_param.get_json(), function (res, status) {
        if ("success" === status && "function" === typeof callback) {
            callback(res);
            return;
        }
    }, "text");
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    读写分控图像配置
 * 参数:
 *    @param { Promise<String> } str_json 请求字串;
 *    @param { Promise<Function> } callback 回调; 直接返回response
 *    @param { Promise<Number> } io 1=写入 || 其他为读取; 默认读取
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-12-30
 *       内容 : 所有代码
************************************************************************************************/
function mc_io_hw_hub_img_rect(str_json, callback, io) {   /* eslint-disable-line */
    callback = "function" === typeof callback ? callback : function () { };

    var obj_param = new mc_sdk_param();

    obj_param.set_json(str_json);
    obj_param.set_cmd("GET_PARAM");
    obj_param.set_func("HW_HUBCARD_IMG_RECT");

    if (!obj_param.get_param_cnt()) {
        callback(false);
        return;
    }

    if (1 === io) {
        obj_param.set_cmd("SET_PARAM");
    }

    // console.log("[读写分控图像配置]", JSON.parse(obj_param.get_json()));
    $.post("/access_shell", obj_param.get_json(), function (res, status) {
        if ("success" === status && "function" === typeof callback) {
            callback(res);
            return;
        }
    }, "text");
}


// ******************** test code ******************** //
// 测试代码: 创建测试请求返回数据; 测试数据
function construct_test_resp(obj_sdk) {   /* eslint-disable-line */
    var ui_cnt = obj_sdk.get_param_cnt();

    for (var index = 0; index < ui_cnt; index++) {
        var str_name = obj_sdk.get_param_name(index);

        obj_sdk.set_attr_val(str_name, "VOLTAGE", get_random() + "");
        obj_sdk.set_attr_val(str_name, "TEMPERATURE", get_random() + "");
        obj_sdk.set_attr_val(str_name, "HUMIDITY", (get_random() + ""));
        obj_sdk.set_attr_val(str_name, "PORT_STATE", (0 === (Math.random() * 10).toFixed() % 2 ? 1 : 0 ) + "" );
        obj_sdk.set_attr_val(str_name, "ONOFFLOG", get_onoff());
        obj_sdk.set_attr_val(str_name, "ERR_PKT_CNT", (Math.random() * 100).toFixed() + "");
    }

    function get_random() {
        return (Math.random() * 10).toFixed(2) + "";
    }

    function get_onoff() {
        // debugger;
        var ui_num = Math.random() * 20;
        var str_onoff = "";
        var ui_i = 0;

        while (ui_i < ui_num) {
            var str_on_or_off = (0 === (Math.random() * 10).toFixed() % 2 ? 1 : 0 );

            str_onoff += "(" + str_on_or_off + ":" +  ( new mc_ui_logger().get_system_time().replace(/[\[\]]/g, '') )  + "" + "),";   /* eslint-disable-line */
            ui_i++;
        }

        return str_onoff;
    }
    // console.log(JSON.parse(obj_sdk.get_json()));
}

function construct_test_hub(port) {   /* eslint-disable-line */
    // 测试代码
    port = port || 0;
    var str = "";

    for (let i = 0; i < port; i++) {
        // str += Number((Math.random() * 10).toFixed(0)) + ",";
    }
    return str;
}
// ******************** test code ******************** //

